home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / tools / czesc_4 / strip / src / strip.c < prev    next >
C/C++ Source or Header  |  1994-08-29  |  14KB  |  640 lines

  1. /*
  2.  *  Strip - Strips debug and symbol hunks from load files.
  3.  *  Copyright (C) 1994 Torsten Poulin
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *             The author can be contacted by mail at
  20.  *               Torsten Poulin
  21.  *               Frankrigsgade 50, 5, 508
  22.  *               DK-2300 Copenhagen S
  23.  *               Denmark
  24.  *             or via email: torsten@diku.dk
  25.  *
  26.  * $Id: Strip.c 37.2 1994/08/28 11:24:06 torsten Rel $
  27.  * $Log: Strip.c $
  28.  * Revision 37.2  1994/08/28  11:24:06  torsten
  29.  * Added a KEEP switch that saves the original file,
  30.  * if no TO destination was given.
  31.  * (Breaks if the filename is 30 chars and already ends
  32.  * with ".orig" - needs to be fixed).
  33.  *
  34.  * Revision 37.1  1994/08/24  23:52:43  torsten
  35.  * Initial revision.
  36.  *
  37.  */
  38.  
  39. #include <exec/types.h>
  40. #include <exec/memory.h>
  41. #include <dos/dos.h>
  42. #include <dos/dosextens.h>
  43. #include <dos/dostags.h>
  44. #include <dos/dosasl.h>
  45. #include <clib/exec_protos.h>
  46. #include <clib/dos_protos.h>
  47. #ifdef __SASC
  48. #include <pragmas/exec_pragmas.h>
  49. #include <pragmas/dos_pragmas.h>
  50. #endif
  51. #include <string.h>
  52. #include <stdarg.h>
  53.  
  54. #include "strip_rev.h"
  55.  
  56. #define PROGNAME "Strip"
  57. #define DOSBase g->dosbase
  58. #define TEMPLATE "FILE/A,TO,QUIET/S,KEEP/S"
  59.  
  60. #define MIN(a,b) ((a)<(b)?(a):(b))
  61. #define LENGTH_MASK 0x3fffffff
  62. #define BUFLEN 4096        /* long words !! */
  63. #define MAXPATH 255        /* assumption */
  64.  
  65. typedef struct {
  66.   struct Library *dosbase;
  67.   struct FileInfoBlock fib;
  68.   struct {
  69.     STRPTR pathname, destination;
  70.     LONG quiet, keep;
  71.   } args;
  72.   ULONG symhunks, dbghunks;
  73.   BPTR in, out;
  74.   LONG *ibptr, *ibend;
  75.   LONG *obptr;
  76.   LONG ib[BUFLEN];
  77.   LONG ob[BUFLEN];        /* length(ob) >= length(ib) !! */
  78.   UBYTE path[MAXPATH+1];
  79. } Global;
  80.  
  81.  
  82. VOID message(enum msgs, Global *);
  83. LONG strip(Global *);
  84. STRPTR destname(STRPTR, Global *);
  85. LONG handlehunk(enum hunktypes, Global *);
  86. LONG do_code_data(enum hunktypes, Global *);
  87. LONG do_reloc(enum hunktypes, Global *);
  88. LONG do_symbol(Global *);
  89. LONG do_debug(Global *);
  90. LONG do_header(enum hunktypes, Global *);
  91. VOID statistics(Global *);
  92. BOOL readLong(LONG *, Global *);
  93. BOOL copyNLongs(LONG, Global *);
  94. BOOL skipNLongs(LONG, Global *);
  95. VOID writeLong(LONG, Global *);
  96. VOID writeNLongs(LONG, Global *);
  97. BOOL flush(Global *);
  98. VOID myPrintf(Global *, char *, ...);
  99. VOID mySPrintf(Global *, char *, char *, ...);
  100.  
  101.  
  102. char const versionID[] = VERSTAG;
  103. char const copyright[] = "$COPYRIGHT:©1994 Torsten Poulin";
  104.  
  105.  
  106. LONG __saveds
  107. entrypoint(VOID)
  108. {
  109.   struct RDArgs *args;
  110.   Global *g;
  111.   LONG   rc = RETURN_OK;
  112.  
  113.   if (g = AllocVec(sizeof(Global), MEMF_ANY | MEMF_CLEAR)) {
  114.     g->obptr = g->ob;
  115.     if (DOSBase = OpenLibrary("dos.library", 37L)) {
  116.       if (args = ReadArgs(TEMPLATE, (LONG *) &g->args, NULL)) {
  117.     if (!g->args.quiet)
  118.       myPrintf(g, "%s %s\n", &versionID[7], ©right[11]);
  119.         rc = strip(g);
  120.         FreeArgs(args);
  121.       }
  122.       else rc = RETURN_FAIL;
  123.       if (rc > RETURN_WARN) PrintFault(IoErr(), PROGNAME);
  124.       CloseLibrary(DOSBase);
  125.     }
  126.     else rc = RETURN_FAIL;
  127.     FreeVec(g);
  128.   }
  129.   else rc = RETURN_FAIL;
  130.   return rc;
  131. }
  132.  
  133.  
  134. enum msgs {
  135.   msg_err_eof,
  136.   msg_notloadfile,
  137.   msg_overlaid,
  138.   msg_unknownhunk,
  139.   msg_nothing,
  140.   msg_pathtoolong,
  141.   msg_cannotopenoutput
  142. };
  143.  
  144. const char *messages[] = {
  145.   "unexpected end of file",
  146.   "not a load file",
  147.   "overlaid load file - not stripped",
  148.   "unrecognized hunk - not stripped",
  149.   "no symbol or debug hunks - file not changed",
  150.   "pathname too long",
  151.   "cannot open output file"
  152. };
  153.  
  154.  
  155. VOID message(enum msgs msg, Global *g)
  156. {
  157.   myPrintf(g, "%s: %s\n", PROGNAME, messages[msg]);
  158. }
  159.  
  160.  
  161. enum hunktypes {
  162.   hunk_code    = 0x03e9,
  163.   hunk_data    = 0x03ea,
  164.   hunk_bss     = 0x03eb,
  165.   hunk_reloc32 = 0x03ec,
  166.   hunk_symbol  = 0x03f0,
  167.   hunk_debug   = 0x03f1,
  168.   hunk_end     = 0x03f2,
  169.   hunk_header  = 0x03f3,
  170.   hunk_overlay = 0x03f5,
  171.   hunk_break   = 0x03f6
  172. };
  173.  
  174.  
  175. LONG strip(Global *g)
  176. {
  177.   LONG rc = RETURN_OK, len;
  178.   enum hunktypes hunk;
  179.   STRPTR from, destination;
  180.   BPTR olddir, dir;
  181.  
  182.   from = FilePart(g->args.pathname);
  183.   if ((len = PathPart(g->args.pathname) - g->args.pathname) > MAXPATH) {
  184.     message(msg_pathtoolong, g);
  185.     return RETURN_FAIL;
  186.   }
  187.  
  188.   if (len) memcpy(g->path, g->args.pathname, len);
  189.  
  190.   if (dir = Lock(g->path, SHARED_LOCK)) {
  191.     olddir = CurrentDir(dir);
  192.  
  193.     if (g->in = Open(from, MODE_OLDFILE)) {
  194.  
  195.       destination = destname(from, g);
  196.       if (g->out = Open(destination, MODE_NEWFILE)) {
  197.  
  198.     /*
  199.      * Ready, set, go ...
  200.      */
  201.  
  202.     if (readLong((LONG *) &hunk, g)) {
  203.       if (hunk != hunk_header) message(msg_notloadfile, g);
  204.       else
  205.         do {
  206.           rc = handlehunk(hunk, g);
  207.         } while (rc == RETURN_OK && readLong((LONG *) &hunk, g));
  208.       flush(g);
  209.       if (rc == RETURN_OK) statistics(g);
  210.     }
  211.     Close(g->out);
  212.  
  213.     /*
  214.      * Set the protection flags and the comment
  215.      */
  216.  
  217.     if (ExamineFH(g->in, &g->fib)) {
  218.       SetComment(destination, g->fib.fib_Comment);
  219.       SetProtection(destination,
  220.             g->fib.fib_Protection & ~(FIBF_ARCHIVE));
  221.     }
  222.       }
  223.       else {
  224.     rc = RETURN_FAIL;
  225.     message(msg_cannotopenoutput, g);
  226.       }
  227.  
  228.       Close(g->in);
  229.     }
  230.     else rc = RETURN_FAIL;
  231.  
  232.     /*
  233.      * If nothing was changed and no destination was
  234.      * specified, we just remove the output file.
  235.      * Ditto if something went wrong.
  236.      */
  237.  
  238.     if ((!g->symhunks && !g->dbghunks && !g->args.destination)
  239.     || rc == RETURN_ERROR)
  240.       DeleteFile(destination);
  241.     else if (!g->args.destination) {
  242.       /*
  243.        * Otherwise we replace the original file
  244.        * unless, of course, we were told to keep it...
  245.        * (in which case we back it up with a .orig
  246.        *  extension).
  247.        */
  248.       if (g->args.keep) {
  249.     /* This is a bit ugly - reusing part
  250.      * of the FileInfoBlock; we ought to be
  251.      * ashamed...
  252.      */
  253.     strcpy(g->fib.fib_FileName, from);
  254.     if (strlen(g->fib.fib_FileName) > 25)
  255.       g->fib.fib_FileName[25] = '\0';
  256.     strcat(g->fib.fib_FileName, ".orig");
  257.     Rename(from, g->fib.fib_FileName);
  258.       }
  259.       else DeleteFile(from);
  260.       Rename(destination, from);
  261.     }
  262.  
  263.     dir = CurrentDir(olddir);
  264.     UnLock(dir);
  265.   }
  266.   else rc = RETURN_ERROR;
  267.  
  268.   return rc;
  269. }
  270.  
  271.  
  272. STRPTR destname(STRPTR from, Global *g)
  273. {
  274.   STRPTR name = g->args.destination;
  275.   BPTR lock;
  276.  
  277.   if (!name) {
  278.     /*
  279.      * Create a reasonably unlikely file name
  280.      */
  281.     mySPrintf(g, g->path, "_strip!%lx!", FindTask(NULL));
  282.     name = g->path;
  283.   }
  284.  
  285.   if (lock = Lock(name, SHARED_LOCK)) {
  286.     if (Examine(lock, &g->fib) &&
  287.     (g->fib.fib_DirEntryType == ST_ROOT ||
  288.      g->fib.fib_DirEntryType == ST_USERDIR ||
  289.      g->fib.fib_DirEntryType == ST_LINKDIR)) {
  290.       /*
  291.        * Name is a directory.
  292.        * Tack on the name of the original file:
  293.        */
  294.       strcpy(g->path, name);
  295.       AddPart(g->path, from, MAXPATH);
  296.       name = g->path;
  297.     }
  298.     UnLock(lock);
  299.   }
  300.   return name;
  301. }
  302.  
  303.  
  304. LONG handlehunk(enum hunktypes hunk, Global *g)
  305. {
  306.   LONG rc = RETURN_OK, size;
  307.  
  308.   switch (hunk & 0xfff) {
  309.   case hunk_code:
  310.   case hunk_data:    rc = do_code_data(hunk, g); break;
  311.   case hunk_bss:     writeLong(hunk, g);
  312.                      if (readLong(&size, g)) writeLong(size, g);
  313.                      else {
  314.                message(msg_err_eof, g);
  315.                rc = RETURN_ERROR;
  316.              }
  317.                      break;
  318.   case hunk_reloc32: rc = do_reloc(hunk, g); break;
  319.   case hunk_symbol:  rc = do_symbol(g); break;
  320.   case hunk_debug:   rc = do_debug(g); break;
  321.   case hunk_end:     writeLong(hunk, g); break;
  322.   case hunk_header:  rc = do_header(hunk, g); break;
  323.   case hunk_overlay:
  324.   case hunk_break:   message(msg_overlaid, g);
  325.                      rc = RETURN_ERROR;
  326.                      break;
  327.   default:           message(msg_unknownhunk, g);
  328.                      rc = RETURN_ERROR;
  329.                      break;
  330.   }
  331.   return rc;
  332. }
  333.  
  334.  
  335. LONG do_code_data(enum hunktypes hunk, Global *g)
  336. {
  337.   LONG rc = RETURN_OK;
  338.   LONG lwords;
  339.  
  340.   writeLong(hunk, g);
  341.   if (readLong(&lwords, g)) {
  342.     writeLong(lwords, g);
  343.     lwords &= LENGTH_MASK;
  344.     if (!copyNLongs(lwords, g)) rc = RETURN_ERROR;
  345.   }
  346.   else rc = RETURN_ERROR;
  347.  
  348.   if (rc != RETURN_OK) message(msg_err_eof, g);
  349.   return rc;
  350. }
  351.  
  352.  
  353. LONG do_reloc(enum hunktypes hunk, Global *g)
  354. {
  355.   LONG rc = RETURN_OK, offsets;
  356.   
  357.   writeLong(hunk, g);
  358.  
  359.   do {
  360.     /*
  361.      * # of offsets
  362.      */
  363.     if (readLong(&offsets, g)) {
  364.       writeLong(offsets, g);
  365.  
  366.       if (!offsets) break;
  367.  
  368.       /*
  369.        * copy the hunk number and the offsets
  370.        */
  371.       if (!copyNLongs(++offsets, g)) rc = RETURN_ERROR;
  372.     }
  373.     else rc = RETURN_ERROR;
  374.   } while (rc == RETURN_OK);
  375.  
  376.   if (rc != RETURN_OK) message(msg_err_eof, g);
  377.   return rc;
  378. }
  379.  
  380.  
  381. LONG do_symbol(Global *g)
  382. {
  383.   LONG rc = RETURN_OK, namelen;
  384.  
  385.   g->symhunks++;
  386.  
  387.   do {
  388.     /*
  389.      * Length of symbol name
  390.      */
  391.     if (readLong(&namelen, g)) {
  392.       if (!namelen) break;
  393.  
  394.       /*
  395.        * copy the name and the symbol value
  396.        */
  397.       if (!skipNLongs(++namelen, g)) rc = RETURN_ERROR;
  398.     }
  399.     else rc = RETURN_ERROR;
  400.   } while (rc == RETURN_OK);
  401.   
  402.   if (rc != RETURN_OK) message(msg_err_eof, g);
  403.   return rc;
  404. }
  405.  
  406.  
  407. LONG do_debug(Global *g)
  408. {
  409.   LONG rc = RETURN_OK;
  410.   LONG lwords;
  411.  
  412.   g->dbghunks++;
  413.  
  414.   if (readLong(&lwords, g)) {
  415.     lwords &= LENGTH_MASK;
  416.     if (!skipNLongs(lwords, g))    rc = RETURN_ERROR;
  417.   }
  418.   else rc = RETURN_ERROR;
  419.  
  420.   if (rc != RETURN_OK) message(msg_err_eof, g);
  421.   return rc;
  422. }
  423.  
  424.  
  425. LONG do_header(enum hunktypes hunk, Global *g)
  426. {
  427.   LONG rc = RETURN_OK;
  428.   LONG size, first, last;
  429.  
  430.   writeLong(hunk, g);
  431.  
  432.   do {
  433.     /* Copy names of resident libraries, if any
  434.      */
  435.     if (readLong(&size, g)) writeLong(size, g);
  436.     else rc = RETURN_ERROR;
  437.     if (!copyNLongs(size, g)) rc = RETURN_ERROR;
  438.   } while (rc == RETURN_OK && size != 0);
  439.  
  440.   if (rc == RETURN_OK)
  441.     /*
  442.      * Hunk table size
  443.      */
  444.     if (readLong(&size, g)) {
  445.       writeLong(size, g);
  446.       /*
  447.        * First hunk #
  448.        */
  449.       if (readLong(&first, g)) {
  450.     writeLong(first, g);
  451.     /*
  452.      * Last hunk #
  453.      */
  454.     if (readLong(&last, g)) {
  455.       writeLong(last, g);
  456.       /*
  457.        * Copy the table contents
  458.        */
  459.       if (!copyNLongs(last - first + 1, g)) rc = RETURN_ERROR;
  460.     }
  461.     else rc = RETURN_ERROR;
  462.       }
  463.       else rc = RETURN_ERROR;
  464.     }
  465.     else rc = RETURN_ERROR;
  466.  
  467.   if (rc != RETURN_OK) message(msg_err_eof, g);
  468.   return rc;
  469. }
  470.  
  471.  
  472. VOID statistics(Global *g)
  473. {
  474.   if (!g->args.quiet)
  475.     if (g->symhunks || g->dbghunks)
  476.       myPrintf(g, "%s: removed - symbol hunks: %ld, debug hunks: %ld\n",
  477.            PROGNAME, g->symhunks, g->dbghunks);
  478.     else message(msg_nothing, g);
  479. }
  480.  
  481.  
  482. /*
  483.  * Custom buffered I/O functions
  484.  */
  485.  
  486. BOOL readLong(LONG *v, Global *g)
  487. {
  488.   LONG rlen;
  489.  
  490.   if (g->ibptr >= g->ibend) {
  491.     g->ibptr = g->ib;
  492.     if ((rlen = Read(g->in, g->ib, BUFLEN * sizeof(LONG))) <= 0)
  493.       return FALSE;        /* error or EOF */
  494.     g->ibend = g->ib + (rlen / sizeof(LONG));
  495.   }
  496.   *v = *g->ibptr++;
  497.   return TRUE;
  498. }
  499.  
  500.  
  501. /*
  502.  * Copy n LONGs from the input to the output.
  503.  */
  504.  
  505. BOOL copyNLongs(LONG n, Global *g)
  506. {
  507.   LONG count, read;
  508.  
  509.   count = g->ibend - g->ibptr;
  510.   count = MIN(n, count);
  511.  
  512.   /*
  513.    * copy buffered input data to the output file.
  514.    */
  515.  
  516.   if (n > 0) {
  517.     writeNLongs(count, g);
  518.     g->ibptr += count;
  519.     n -= count;
  520.   }
  521.  
  522.   /*
  523.    * copy any remaining data directly from
  524.    * the input file to the output via
  525.    * the currently empty input buffer.
  526.    */
  527.  
  528.   if (n > 0) {
  529.     count = MIN(BUFLEN, n);
  530.     while ((read = Read(g->in, g->ib, count * sizeof(LONG))) > 0) {
  531.       g->ibptr = g->ib;
  532.       /*
  533.        * I wonder whether the following is a dangerous
  534.        * assumption given that the AmigaDOS Manual states
  535.        * that "[u]sually Read() will try to fill up your
  536.        * buffer before returning":
  537.        */
  538.       read /= sizeof(LONG);
  539.       writeNLongs(read, g);
  540.       if ((n -= read) == 0) break;
  541.       count = MIN(BUFLEN, n);
  542.     }
  543.     if (read <= 0) return FALSE;
  544.     /*
  545.      * The input buffer has become invalid,
  546.      * so we force a physical read by marking
  547.      * the buffer as empty.
  548.      */
  549.     g->ibptr = g->ibend;
  550.   }
  551.  
  552.   return TRUE;
  553. }
  554.  
  555.  
  556. BOOL skipNLongs(LONG n, Global *g)
  557. {
  558.   LONG inbuffer;
  559.  
  560.   if (n > 0) {
  561.     inbuffer = g->ibend - g->ibptr + 1;
  562.     if (n <= inbuffer) g->ibptr += n;
  563.     else {
  564.       n -= inbuffer;
  565.       if (Seek(g->in, n * sizeof(LONG), OFFSET_CURRENT) < 0)
  566.     return FALSE;        /* beyond end of file? */
  567.       /*
  568.        * The input buffer has become invalid,
  569.        * so we force a physical read by marking
  570.        * the buffer as empty.
  571.        */
  572.       g->ibptr = g->ibend;
  573.     }
  574.   }
  575.   return TRUE;
  576. }
  577.  
  578.  
  579. VOID writeLong(LONG v, Global *g)
  580. {
  581.   if (g->obptr - g->ob == BUFLEN && !flush(g)) /* write error */;
  582.   *g->obptr++ = v;
  583. }
  584.  
  585.  
  586. /*
  587.  * Write n LONGs from g->ibptr to the output buffer.
  588.  * Assumes that the output buffer is at least as big
  589.  * as the input buffer.
  590.  */
  591.  
  592. VOID writeNLongs(LONG n, Global *g)
  593. {
  594.   LONG obfree, count;
  595.  
  596.   obfree = BUFLEN - (g->obptr - g->ob);
  597.  
  598.   if ((count = MIN(n, obfree)) > 0) {
  599.     memcpy(g->obptr, g->ibptr, count * sizeof(LONG));
  600.     g->obptr += count;
  601.   }
  602.  
  603.   if (n > obfree) {
  604.     flush(g);
  605.     n -= count;
  606.     memcpy(g->obptr, g->ibptr + count, n * sizeof(LONG));
  607.     g->obptr += n;
  608.   }
  609. }
  610.  
  611.  
  612. BOOL flush(Global *g)
  613. {
  614.   LONG bytes = (g->obptr - g->ob) * sizeof(LONG);
  615.  
  616.   if (bytes && Write(g->out, g->ob, bytes) < 0) return FALSE;
  617.   g->obptr = g->ob;
  618.   return TRUE;
  619. }
  620.  
  621.  
  622. VOID myPrintf(Global *g, char *fmt, ...)
  623. {
  624.   va_list ap;
  625.  
  626.   va_start(ap, fmt);
  627.   VPrintf(fmt, (LONG *) ap);
  628.   va_end(ap);
  629. }
  630.  
  631.  
  632. VOID mySPrintf(Global *g, char *s, char *fmt, ...)
  633. {
  634.   va_list ap;
  635.  
  636.   va_start(ap, fmt);
  637.   RawDoFmt(fmt, (LONG *) ap, (void (*)) "\x16\xc0\x4e\x75", s);
  638.   va_end(ap);
  639. }
  640.